package com.settlement.system.service.impl;

import com.settlement.system.common.enums.BillTypeEnum;
import com.settlement.system.common.enums.ChannelEnum;
import com.settlement.system.common.enums.UnificationProblemDescEunm;
import com.settlement.system.common.enums.UnificationStatusEunm;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.common.util.common.DateUtil;
import com.settlement.system.common.util.common.JsonUtil;
import com.settlement.system.common.util.common.SystemUserUtil;
import com.settlement.system.mapper.*;
import com.settlement.system.mapper.security.userdetails.SysUserDetails;
import com.settlement.system.model.entity.common.SystemUser;
import com.settlement.system.model.entity.common.TblReceiveRefundEditor;
import com.settlement.system.model.entity.common.TblUnificationBillDetail;
import com.settlement.system.service.ITblReceiveRefundEditorService;
import com.settlement.system.service.ITblRrBillTypeService;
import com.settlement.system.service.ITblUnificationBillDetailService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.*;

/**
 * 统一账单明细 服务实现类
 *
 * @author Ximi
 * @since 2020-07-01
 */
@Slf4j
@Service
public class TblUnificationBillDetailServiceImpl extends BaseServiceImpl implements ITblUnificationBillDetailService {

    private static List<String> beginFunds = null;
    private static List<String> tailFunds = null;

    final String shoukuan = "首款";
    final String weikuan = "尾款";

    static {
        beginFunds = new ArrayList<>();
        beginFunds.add("发货明细_首款");
        beginFunds.add("往期售后明细_首款");

        tailFunds = new ArrayList<>();
        tailFunds.add("发货明细_尾款");
        tailFunds.add("售后明细");
        tailFunds.add("往期售后明细");
        tailFunds.add("订单赔付明细");
        tailFunds.add("在途售后明细");
        tailFunds.add("违规明细");
        tailFunds.add("往期售后明细_尾款");
        tailFunds.add("营销费用");
    }

    /*@Reference(version = "${dubbo.acs.api.version}", timeout = 6000)
    private RrPushNcApi rrPushNcApi;*/

    /*@Reference(version = "${dubbo.acs.api.version}", timeout = 6000)
    private UnificationBillDetailApi unificationBillDetailApi;*/

    @Resource
    private TblUnificationBillDetailMapper tblUnificationBillDetailMapper;

    @Resource
    private TblAkcTransportAfterSaleMapper tblAkcTransportAfterSaleMapper;

    @Resource
    private TblAkcAfterSaleDetailMapper tblAkcAfterSaleDetailMapper;

    @Resource
    private TblAkcCompensateDetailMapper tblAkcCompensateDetailMapper;

    @Resource
    private TblAkcPastAfterSaleDetailMapper tblAkcPastAfterSaleDetailMapper;

    @Resource
    private TblAkcSaleDetailMapper tblAkcSaleDetailMapper;

    @Resource
    private TblAkcViolateDetailMapper tblAkcViolateDetailMapper;

    @Resource
    private ITblReceiveRefundEditorService tblReceiveRefundEditorService;

    @Resource
    private ITblRrBillTypeService tblRrBillTypeService;

    @Override
    public BaseMapper init() {
        return tblUnificationBillDetailMapper;
    }

    @Override
    public TblUnificationBillDetail getFoot(Map<String, Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.getFoot(params);
        } catch (Exception ex) {
            log.error("获取合计异常", ex);
            throw new ServiceException("获取合计异常", ex);
        }
    }

    @Override
    @Transactional(rollbackFor = {ServiceException.class},noRollbackFor = {DuplicateKeyException.class})
    public void deleteAkcDataByParams(Map<String,Object> params) throws ServiceException {
        try {
            // 删除统一账单中相关数据
            tblUnificationBillDetailMapper.deleteAkcDataByParams(params);
            // 删除原始明细中相关数据
            String actionId = (String) params.get("actionId");
            String activityType = (String) params.get("activityType");

            if(weikuan.equals(activityType)){
                //售后明细
                tblAkcAfterSaleDetailMapper.deleteByActionId(actionId);
                // 在途售后
                tblAkcTransportAfterSaleMapper.deleteByActionId(actionId);
                //违规明细
                tblAkcViolateDetailMapper.deleteByActionId(actionId);
                //往期售后明细
                tblAkcPastAfterSaleDetailMapper.deleteByActionId(actionId,activityType);
                //订单赔付明细
                tblAkcCompensateDetailMapper.deleteByActionId(actionId);

            }else if(shoukuan.equals(activityType)){
                //发货明细,
                tblAkcSaleDetailMapper.deleteByActionId(actionId);
                // 往期售后明细
                tblAkcPastAfterSaleDetailMapper.deleteByActionId(actionId,activityType);
            }

        } catch (Exception ex) {
            log.error("deleteAkcDataByParams error", ex);
            throw new ServiceException("deleteAkcDataByParams error", ex);
        }
    }

    @Override
    public Integer getAkcPushedCount(String actionId, String billType) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.getAkcPushedCount(actionId, getRelatedbillTypes(billType));
        } catch (Exception ex) {
            log.error("获取爱库存已经推送数量异常", ex);
            throw new ServiceException("获取爱库存已经推送数量异常", ex);
        }
    }

    @Override
    public Integer updateAkcDate(String actionId, String billType, Date date) throws ServiceException {
        try {
            List<String> list = new ArrayList<>();
            List<String> relatedbillTypes = getRelatedbillTypes(billType);
            for(String relatedbillType:relatedbillTypes){
                String s = BillTypeEnum.convertToNo(relatedbillType);
                list.add(s);
            }
            return tblUnificationBillDetailMapper.updateAkcDate(actionId, list, date);
        } catch (Exception ex) {
            log.error("更新爱库存日期异常", ex);
            throw new ServiceException("更新爱库存日期异常", ex);
        }
    }

    @Override
    public String billSummary(Map<String, Object> params) throws ServiceException {
        try {
            // 先找出本账户对应的editNo
            SysUserDetails user = SecurityUtils.getUser();;
            String username = user.getUsername();
            TblReceiveRefundEditor editor = tblReceiveRefundEditorService.getEditorByLoginName(username);

            // 当前用户不是制单人身份，提示"撤销人非制单人，故无法撤销！"
            if(editor==null){
                return "不得生成汇总，生成人不在制单人配置表中，请维护。";
            }

            if (tblUnificationBillDetailMapper.getNotStatusCount(UnificationStatusEunm.complete_match.getNo(), params) > 0) {
                return "只有状为[完成匹配]的明细,才能生成汇总";
            }
            params.put("status", UnificationStatusEunm.complete_match.getNo());
            // 汇总时，包括不参与记账的，生成凭证时，只处理参与记账的
            tblUnificationBillDetailMapper.updateStatus(UnificationStatusEunm.waiting_push_nc.getNo(), user.getUsername(), params);
            params.remove("status");
            /*rrPushNcApi.billSummary(params);*/
        } catch (Exception ex) {
            log.error("汇总异常", ex);
            throw new ServiceException("汇总异常", ex);
        }
        return null;
    }



    @Override
    public void updateMatch(List<TblUnificationBillDetail> list) throws ServiceException {
        try {
            for (TblUnificationBillDetail detail : list) {
                Integer problemDesc = UnificationProblemDescEunm.encode(detail);
                detail.setProblemDesc(problemDesc);
                detail.setUpdateUser(SystemUserUtil.getSystemUser().getUsername());
                tblUnificationBillDetailMapper.updateMatch(detail);
                tblUnificationBillDetailMapper.refreshNoMatchOne(detail);
            }
        } catch (Exception ex) {
            log.error("更新匹配异常", ex);
            throw new ServiceException("更新匹配异常", ex);
        }
    }

    @Override
    public Integer refreshNoMatch(Map<String, Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.refreshNoMatch(params);
        } catch (Exception ex) {
            log.error("更新匹配异常", ex);
            throw new ServiceException("更新匹配异常", ex);
        }
    }

    @Override
    public Integer selectOneByBatchNumber(long batchNumber) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.selectOneByBatchNumber(batchNumber);
        } catch (Exception ex) {
            log.error("selectOneByBatchNumber error", ex);
            throw new ServiceException("selectOneByBatchNumber error", ex);
        }
    }

    @Override
    public Long selectTheNewestBatchNumber() throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.selectTheNewestBatchNumber();
        } catch (Exception ex) {
            log.error("selectTheNewestBatchNumber error", ex);
            throw new ServiceException("selectTheNewestBatchNumber error", ex);
        }
    }



    @Override
    public Integer refreshNoMatchByActionIdOfAkc(String actionId) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.refreshNoMatchByActionIdOfAkc(actionId);
        } catch (Exception ex) {
            log.error("更新匹配异常", ex);
            throw new ServiceException("更新匹配异常", ex);
        }
    }

    @Override
    public Integer refreshAkcDate(Map<String, Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.refreshAkcDate(params);
        } catch (Exception ex) {
            log.error("刷新爱库存日期", ex);
            throw new ServiceException("刷新爱库存日期", ex);
        }
    }

    @Override
    public String checkIfCloseAccount(Map<String, Object> params) throws ServiceException{
        try {
            TblUnificationBillDetail detail = tblUnificationBillDetailMapper.selectCloseAccountInfo(params);
            Date nullOutDateAkc = DateUtil.parseToDate("2000-01-01 00:00:00","yyyy-MM-dd HH:mm:ss");
            if (detail !=null) {
                if(ChannelEnum.AKC.getNo().equals(detail.getChannelNo()) && detail.getOutDate().getTime() == nullOutDateAkc.getTime()){
                    // 爱库存的，outDate为空的，可以刷新
                }else{
                    Date realCloseAccountDate = detail.getRealCloseAccountDate();
                    Date nullCloseAccountDate = DateUtil.parseToDate("2100-01-01 00:00:00","yyyy-MM-dd HH:mm:ss");
                    if(realCloseAccountDate.getTime() == nullCloseAccountDate.getTime()){
                        if(StringUtils.isNotEmpty(detail.getNcShopNo())){
                            return "该"+detail.getNcShopName()+"店铺，请维护锁账信息。";
                        }else if(ChannelEnum.OR.getName().equals(detail.getChannelName()) && StringUtils.isEmpty(detail.getNcShopNo())){
                            return "该"+detail.getShopAccount()+"线下打款账号，请维护锁账信息。";
                        }else{
                            if(StringUtils.isEmpty(detail.getNcShopNo()) && StringUtils.isEmpty(detail.getShopAccount())){
                                return "该"+detail.getUnificationBillId()+"统一账单ID，NC店铺编码为空，店铺账号为空，请维护锁账信息。";
                            }
                            return "该"+detail.getUnificationBillId()+"统一账单ID，请维护锁账信息。";
                        }
                    }else{
                        if(StringUtils.isNotEmpty(detail.getNcShopNo())){
                            log.info("该"+detail.getNcShopName()+"店铺，"+detail.getThreeLevelChannelNo()+"三级来源，已被锁账至"+ DateUtil.getDate(detail.getRealCloseAccountDate(),"yyyy-MM-dd")+"，不允许刷新。");
                        }else if(ChannelEnum.OR.getName().equals(detail.getChannelName()) && StringUtils.isEmpty(detail.getNcShopNo())){
                            log.info("该"+detail.getShopAccount()+"线下打款账号，已被锁账至"+DateUtil.getDate(detail.getRealCloseAccountDate(),"yyyy-MM-dd")+"，不允许刷新。");
                        }
                        log.info("该数据已锁账，不允许刷新！");
                        return "该数据已锁账，不允许刷新！";
                    }
                }
            }
        } catch (Exception ex) {
            throw new ServiceException("刷新异常", ex);
        }
        return null;
    }

    @Override
    public String refresh(Map<String, Object> params) throws ServiceException {
        try {
            String message = checkIfCloseAccount(params);
            if(StringUtils.isNotEmpty(message)){
                return message;
            }
            /*unificationBillDetailApi.refreshNoMatch(params);*/
        } catch (Exception ex) {
            throw new ServiceException("刷新异常", ex);
        }
        return null;
    }

    @Override
    public void deleteByUnificationBillIds(String minUnificationBillId, String maxUnificationBillId) {
        tblUnificationBillDetailMapper.deleteByUnificationBillIds(minUnificationBillId,maxUnificationBillId);
    }

    @Override
    public int validateCloseDate(Map<String,Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.validateCloseDate(params);
        } catch (Exception e) {
           throw new ServiceException(e);
        }
    }

    @Override
    public int selectCountByBatchNumberAndCpnStatus(Map<String,Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.selectCountByBatchNumberAndCpnStatus(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public int selectCountByBatchNumberAndNotCmStatus(Map<String,Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.selectCountByBatchNumberAndNotCmStatus(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public int selectCountByBatchNumberAndNotCreateUser(Map<String,Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.selectCountByBatchNumberAndNotCreateUser(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public List<TblUnificationBillDetail> getDeleteDate(Map<String, Object> params) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.getDeleteDate(params);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public boolean deleteByBatchNumber(Map<String, Object> params) throws ServiceException {
        try {
        	int num = tblUnificationBillDetailMapper.deleteByBatchNumber(params);
        	if (num > 0) {
            	return true;
            }
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        return false;
    }

    /**
     * @param billType
     * @return
     */
    private List<String> getRelatedbillTypes(String billType) {
        if (shoukuan.equals(billType)) {
            return beginFunds;
        }
        if (weikuan.equals(billType)) {
            return tailFunds;
        }
        return Arrays.asList(billType);
    }

    @Override
    @Transactional(rollbackFor = {ServiceException.class}, noRollbackFor = {DuplicateKeyException.class})
    public <ModelType> Integer saveNoDuplicateList(List<ModelType> list) throws ServiceException, DuplicateKeyException {
        List<TblUnificationBillDetail> billDetails = new ArrayList<>();
        List<TblUnificationBillDetail> duplicateList = new ArrayList<>();
        //爱库存统一账单为空，数据表存为2000年
        Date nullOutDateAkc = DateUtil.parseToDate("2000-01-01 00:00:00","yyyy-MM-dd HH:mm:ss");
        for (int index = 0; index < list.size(); index++) {
            TblUnificationBillDetail detail = (TblUnificationBillDetail) list.get(index);
            //爱库存统一账单为空，数据表存为2000年
            if(ChannelEnum.AKC.getNo().equals(detail.getChannelNo()) && detail.getOutDate() == null){
                detail.setOutDate(nullOutDateAkc);
            }
            billDetails.add(detail);
            if (billDetails.size() == 50 || index == list.size() - 1) {
                try {
                    tblUnificationBillDetailMapper.batchAdd(billDetails);
                } catch (Exception ex) {
                    if (ex.getCause() != null && ex.getCause() instanceof SQLIntegrityConstraintViolationException) {
                        duplicateList.addAll(saveUnique(billDetails));
                    } else {
                        log.error("批量保存统一报表异常", ex);
                        throw new ServiceException("批量保存统一报表异常", ex);
                    }
                }
                billDetails.clear();
            }
        }
        if (duplicateList.size() > 0) {
            throw new DuplicateKeyException(JsonUtil.getJsonOrToString(duplicateList));
        }
        return list.size();
    }

    private List<TblUnificationBillDetail> saveUnique(List<TblUnificationBillDetail> data) throws ServiceException {
        List<TblUnificationBillDetail> duplicateList = new ArrayList<>();
        for (TblUnificationBillDetail info : data) {
            try {
                tblUnificationBillDetailMapper.insert(info);
            } catch (Exception ex) {
                if (ex.getCause() != null && ex.getCause() instanceof SQLIntegrityConstraintViolationException) {
                    duplicateList.add(info);
                } else {
                    log.error("保存统一报表异常", ex);
                    throw new ServiceException("保存统一报表异常", ex);
                }
            }
        }
        return duplicateList;
    }

    /**
     * 修改批量保存的逻辑
     *
     * @param list
     * @param <ModelType>
     * @throws ServiceException
     */
    @Override
    public <ModelType> void save(List<ModelType> list) throws ServiceException {
        tblUnificationBillDetailMapper.batchAdd((List<TblUnificationBillDetail>) list);
    }

    @Override
    public int updateOriginBillProjectBySerialNoList(List<String> serialNoList) throws ServiceException {
        try {
            return tblUnificationBillDetailMapper.updateOriginBillProjectBySerialNoList(serialNoList);
        } catch (Exception e) {
            log.error("updateOriginBillProjectBySerialNoList error", e);
            throw new ServiceException(e);
        }
    }

    @Override
    public void refreshShareOrNot(Map<String,Object> params){
        tblUnificationBillDetailMapper.refreshShareOrNot(params);
    }

    @Override
    public void refreshBeforeOrAfterTicket(Map<String,Object> params){
        tblUnificationBillDetailMapper.refreshBeforeOrAfterTicket(params);
    }

    @Override
    public TblUnificationBillDetail selectOneByParam(Map<String, Object> params) throws ServiceException {
        return tblUnificationBillDetailMapper.selectOneByParam(params);
    }
}

